package com.tjl.warehouse.annotation;

import cn.hutool.core.util.StrUtil;
import com.tjl.warehouse.common.ErrorCode;
import com.tjl.warehouse.exception.BusinessException;
import com.tjl.warehouse.exception.ThrowUtils;
import com.tjl.warehouse.utils.JWTUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * token校验切面类
 * @author Tang
 * @createDate 2024/5/11
 */
@Component
@Aspect
public class AuthTokenAspect {

    // token请求头key
    private static final String TOKEN_HEADER_KEY = "Token";

    @Around("@annotation(AuthToken) || @within(AuthToken)")
    public Object handleAuth(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取参数
        var args = joinPoint.getArgs();

        // 获取目标方法或类的@AuthToken注解
        AuthToken annotation = getEffectiveAuthToken(joinPoint);

        if (annotation == null) {
            return joinPoint.proceed(args);
        }

        // 如果未设置排除属性才校验
        if (!annotation.exclude()) {
            validateToken((ServletRequestAttributes) RequestContextHolder.getRequestAttributes(), annotation);
        }

        // 继续执行原方法
        return joinPoint.proceed(args);
    }

    //获取请求头中的token并且校验
    private void validateToken(ServletRequestAttributes attributes, AuthToken authToken) throws Throwable {
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String token = request.getHeader(TOKEN_HEADER_KEY);
            if (token == null || StrUtil.isBlank(token)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"token为空");
            } else {
                boolean tokenExpired = JWTUtils.isTokenExpired(token);
                ThrowUtils.throwIf(tokenExpired, ErrorCode.NO_AUTH_ERROR);
            }
        }
    }



    // 获取有效的@AuthToken注解，优先查找方法，其次查找类
    private AuthToken getEffectiveAuthToken(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AuthToken methodLevelAnnotation = signature.getMethod().getAnnotation(AuthToken.class);
        AuthToken classLevelAnnotation = joinPoint.getTarget().getClass().getAnnotation(AuthToken.class);
        return methodLevelAnnotation != null ? methodLevelAnnotation : classLevelAnnotation;
    }
}
